using System;

using AGG.Transform;
using AGG.Image;
using AGG.VertexSource;
using AGG.UI;
using AGG.RasterizerScanline;

namespace AGG
{
    public class lion_outline_application : MatchParentBoundsWidget
    {
        private AGG.UI.SliderWidget widthSlider;
        private AGG.UI.CheckBoxWidget renderAsScanlineCheckBox;
        private AGG.UI.CheckBoxWidget renderAccurateJoinsCheckBox;

        private LionShape lionShape = new LionShape();
        ScanlineRasterizer rasterizer = new ScanlineRasterizer();
        ScanlineCachePacked8 scanlineCache = new ScanlineCachePacked8();
        double angle = 0;
        double lionScale = 1.0;
        double skewX = 0;
        double skewY = 0;

        public lion_outline_application()
        {
            widthSlider = new AGG.UI.SliderWidget(5, 5, 150, 12);
            renderAsScanlineCheckBox = new AGG.UI.CheckBoxWidget(160, 5, "Use Scanline Rasterizer");
            renderAsScanlineCheckBox.Checked = false;
            widthSlider.ValueChanged += new SliderWidget.ValueChangedEventHandler(NeedsRedraw);
            renderAsScanlineCheckBox.CheckedStateChanged += new CheckBoxWidget.CheckedStateChangedEventHandler(NeedsRedraw);
            AddChild(widthSlider);
            widthSlider.Transform = Affine.NewIdentity();
            widthSlider.range(0.0, 4.0);
            widthSlider.value(1.0);
            widthSlider.label("Width {0:F2}");

            AddChild(renderAsScanlineCheckBox);
            //renderAsScanlineCheckBox.Transform = Affine.NewIdentity();

            renderAccurateJoinsCheckBox = new CheckBoxWidget(200 + 10.0, 10.0 + 4.0 + 16.0, "Accurate Joins");
            AddChild(renderAccurateJoinsCheckBox);
        }

        void NeedsRedraw(object sender, EventArgs e)
        {
            Invalidate();
        }

        public override void OnDraw(Graphics2D graphics2D)
        {
            int width = (int)graphics2D.DestImage.Width;
            int height = (int)graphics2D.DestImage.Height;


            ImageBuffer pixf = new ImageBuffer();
            pixf.Attach(graphics2D.DestImage, new BlenderBGR());
            ImageClippingProxy clippingProxy = new ImageClippingProxy(pixf);
            clippingProxy.clear(new RGBA_Doubles(1,1,1));

            Affine transform = Affine.NewIdentity();
            transform *= Affine.NewTranslation(-lionShape.Center.x, -lionShape.Center.y);
            transform *= Affine.NewScaling(lionScale, lionScale);
            transform *= Affine.NewRotation(angle + Math.PI);
            transform *= Affine.NewSkewing(skewX / 1000.0, skewY / 1000.0);
            transform *= Affine.NewTranslation(width / 2, height / 2);

            if (renderAsScanlineCheckBox.Checked)
            {
                rasterizer.SetVectorClipBox(0, 0, width, height);

                conv_stroke stroke = new conv_stroke(lionShape.Path);
                stroke.width(widthSlider.value());
                stroke.line_join(math_stroke.line_join_e.round_join);
                VertexSourceApplyTransform trans = new VertexSourceApplyTransform(stroke, transform);
                agg_renderer_scanline.Default.RenderSolidAllPaths(clippingProxy, rasterizer, scanlineCache, trans, lionShape.Colors, lionShape.PathIndex, lionShape.NumPaths);
            }
            else
            {
                double w = widthSlider.value() * transform.GetScale();

                line_profile_aa profile = new line_profile_aa(w, new gamma_none());
                renderer_outline_aa ren = new renderer_outline_aa(clippingProxy, profile);
                rasterizer_outline_aa ras = new rasterizer_outline_aa(ren);

                ras.line_join(renderAccurateJoinsCheckBox.Checked ?
                    rasterizer_outline_aa.outline_aa_join_e.outline_miter_accurate_join 
                    : rasterizer_outline_aa.outline_aa_join_e.outline_round_join); 
                ras.round_cap(true);

                VertexSourceApplyTransform trans = new VertexSourceApplyTransform(lionShape.Path, transform);

                ras.render_all_paths(trans, lionShape.Colors, lionShape.PathIndex, lionShape.NumPaths);
            }

            base.OnDraw(graphics2D);
        }


        void DoTransform(double width, double height, double x, double y)
        {
            x -= width / 2;
            y -= height / 2;
            angle = Math.Atan2(y, x);
            lionScale = Math.Sqrt(y * y + x * x) / 100.0;
        }

        protected bool MoveTheLion(MouseEventArgs mouseEvent)
        {
            double x = mouseEvent.X;
            double y = mouseEvent.Y;
            if (mouseEvent.Button == MouseButtons.Left)
            {
                int width = (int)Width;
                int height = (int)Height;
                DoTransform(width, height, x, y);
                Invalidate();
                return true;
            }

            if (mouseEvent.Button == MouseButtons.Right)
            {
                skewX = x;
                skewY = y;
                Invalidate();
                return true;
            }

            return false;
        }


        public override void OnMouseDown(MouseEventArgs mouseEvent)
        {
        	base.OnMouseDown(mouseEvent);

            if (Focused && MouseCaptured)
            {
                MoveTheLion(mouseEvent);
            }
        }

        public override void OnMouseMove(MouseEventArgs mouseEvent)
        {
        	base.OnMouseMove(mouseEvent);
            if (Focused && MouseCaptured)
            {
                MoveTheLion(mouseEvent);
            }
        }

        public static void StartDemo()
        {
            GuiHalFactory.SetGuiBackend(GuiHalFactory.KnownGuiFactoriesIndexes.WindowsFormsBitmap);
            GuiHalSurface primaryWindow = GuiHalFactory.CreatePrimarySurface(512, 512, GuiHalSurface.CreateFlags.Resizable, GuiHalSurface.PixelFormat.PixelFormatBgr24);

            primaryWindow.Caption = "AGG Example. Lion Outline";

            primaryWindow.AddChild(new lion_outline_application());
            primaryWindow.Run();
        }

        [STAThread]
        public static void Main(string[] args)
        {
        	StartDemo();
        }
    }
}
